package com.inspur.sc.springboot.config;

import com.inspur.sc.springboot.security.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.session.HttpSessionEventPublisher;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyFilterSecurityInterceptor myFilterSecurityInterceptor;

    @Autowired
    private SessionRegistry sessionRegistry;

    @Autowired
    private MyAccessDeniedHandler myAccessDeniedHandler;

    @Autowired
    private MyAuthenticationProcessingFilterEntryPoint authenticationProcessingFilterEntryPoint;

    @Value("${user.ignoring_url}")
    private String [] urls;

    /**
     * 自定义UserDetailsService，从数据库中读取用户信息
     *
     * @return
     */
    @Bean
    UserDetailsService customUserService() { //注册UserDetailsService 的bean
        return new CustomUserService();
    }

    /**
     * user Details Service验证
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserService()).passwordEncoder(passwordEncoder());
    }

    /**
     * 对不需要进行验证的路径进行过滤
     * @param web
     */
    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers(HttpMethod.GET,urls);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        //指定路径，只能那些权限角色才能访问，并且需要登录后才能进行访问
        http.authorizeRequests().antMatchers("/admin/**").hasAuthority("ROLE_ADMIN") .anyRequest().authenticated();

        //登录验证
        http.formLogin().loginPage("/login").failureUrl("/login?error").defaultSuccessUrl("/index").permitAll();

        //退出验证
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/login?logout").invalidateHttpSession(true).deleteCookies("JSESSIONID").permitAll();

        http.rememberMe().tokenValiditySeconds(7 * 24 * 60 * 60).key("springboot").tokenRepository(persistentTokenRepository());

        //Session 会话管理
        http.sessionManagement().invalidSessionUrl("/login?expired").maximumSessions(1).maxSessionsPreventsLogin(true).sessionRegistry(sessionRegistry).expiredUrl("/login?expired");

        http.exceptionHandling().accessDeniedHandler(myAccessDeniedHandler).authenticationEntryPoint(authenticationProcessingFilterEntryPoint);
        http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);
        //跨站防护登录关
        http.csrf().disable();
    }

    /**
     * 设置用户密码的加密方式
     *
     * @return
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Bean
    public SessionRegistry getSessionRegistry() {
        SessionRegistry sessionRegistry = new SessionRegistryImpl();
        return sessionRegistry;
    }

    @Bean
    public ServletListenerRegistrationBean httpSessionEventPublisher() {
        return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
    }

    @Autowired
    private DataSource dataSource;

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }
}
